// web/lib/services/auth.ts

import { API_ENDPOINTS } from "../api/config";
import { BaseService } from "../base/requests";
import {
  LoginRequest,
  LoginResponse,
  RegisterRequest,
  VerificationCodeRequest,
  SendVerificationCodeRequest,
  ResetPasswordRequest,
  User,
  TokenVerifyResponse,
  RefreshTokenRequest,
  RefreshTokenResponse,
  LogoutRequest,
  ChangePasswordRequest,
} from "../types";
import type { ApiResponse } from "../types";
import { EventEmitter } from 'events';

/**
 * 认证服务类
 * 处理用户认证相关的所有操作，包括登录、注册、验证码等功能
 * 实现单例模式，确保全局只有一个认证服务实例
 * @extends {BaseService}
 */
class AuthService extends BaseService {
  private static instance: AuthService;
  /** 访问令牌 */
  private accessToken: string | null = null;
  /** 刷新令牌 */
  private refreshToken: string | null = null;
  /** token检查定时器 */
  private tokenCheckTimer: NodeJS.Timeout | null = null;
  /** token检查间隔（毫秒） */
  private readonly TOKEN_CHECK_INTERVAL = 20 * 60 * 1000; // 20分钟
  private eventEmitter: EventEmitter;

  /**
   * 私有构造函数，初始化认证服务
   * 从本地存储中获取已存储的认证令牌（如果存在）
   * @private
   */
  private constructor() {
    super();
    this.eventEmitter = new EventEmitter();
    if (typeof window !== "undefined") {
      this.accessToken = this.getAccessToken();
      this.refreshToken = this.getRefreshToken();
      if (this.accessToken) {
        this.startTokenCheck();
      }
    }
  }

  /**
   * 获取 AuthService 的单例实例
   * @returns {AuthService} AuthService 实例
   * @static
   */
  static getInstance(): AuthService {
    if (!AuthService.instance) {
      AuthService.instance = new AuthService();
    }
    return AuthService.instance;
  }

  /**
   * 设置认证令牌
   * 同时更新内存中的令牌和 cookie，并启动token检查
   * @param {string} accessToken - 访问令牌
   * @param {string} refreshToken - 刷新令牌
   */
  setTokens(accessToken: string, refreshToken: string) {
    this.accessToken = accessToken;
    this.refreshToken = refreshToken;
    if (typeof window !== "undefined") {
      // 设置 cookie，添加必要的安全属性
      const cookieOptions = {
        path: '/',
        sameSite: 'lax' as const,
        secure: process.env.NODE_ENV === 'production',
        httpOnly: true
      };

      // 设置 access_token cookie
      document.cookie = `access_token=${accessToken}; path=${cookieOptions.path}; max-age=${30 * 60}; SameSite=${cookieOptions.sameSite}${cookieOptions.secure ? '; Secure' : ''}`;
      
      // 设置 refresh_token cookie
      document.cookie = `refresh_token=${refreshToken}; path=${cookieOptions.path}; max-age=${7 * 24 * 60 * 60}; SameSite=${cookieOptions.sameSite}${cookieOptions.secure ? '; Secure' : ''}`;
      
      this.startTokenCheck();
    }
  }

  /**
   * 清除认证令牌
   * 同时清除内存中的令牌和 cookie，并停止token检查
   */
  clearTokens() {
    this.accessToken = null;
    this.refreshToken = null;
    if (typeof window !== "undefined") {
      // 清除 cookie
      document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
      document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
      
      this.stopTokenCheck();
    }
  }

  /**
   * 开始token检查
   * 每20分钟检查一次token有效性
   * @private
   */
  private startTokenCheck() {
    this.stopTokenCheck(); // 确保之前的定时器被清除
    this.tokenCheckTimer = setInterval(() => this.checkToken(), this.TOKEN_CHECK_INTERVAL);
  }

  /**
   * 停止token检查
   * @private
   */
  private stopTokenCheck() {
    if (this.tokenCheckTimer) {
      clearInterval(this.tokenCheckTimer);
      this.tokenCheckTimer = null;
    }
  }

  /**
   * 检查token有效性
   * @private
   */
  private async checkToken() {
    try {
      const response = await this.get<TokenVerifyResponse>(API_ENDPOINTS.auth.verifyToken);
      if (!response.data.valid) {
        await this.handleTokenInvalid();
      }
    } catch (error) {
      console.error('Token验证失败:', error);
      await this.handleTokenInvalid();
    }
  }

  /**
   * 处理token无效的情况
   * @private
   */
  private async handleTokenInvalid() {
    console.log('=== Token 失效处理 ===');
    // 清除内存中的令牌
    this.accessToken = null;
    this.refreshToken = null;
    
    // 清除 cookie
    if (typeof window !== "undefined") {
      document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
      document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";
      console.log('已清除所有认证令牌');
    }
    
    // 停止令牌检查
    this.stopTokenCheck();
    
    // 触发 token 失效事件
    this.eventEmitter.emit('tokenInvalid');
  }

  /**
   * 刷新访问令牌
   * @returns {Promise<void>}
   * @private
   */
  private async refreshAccessToken(): Promise<void> {
    if (!this.refreshToken) {
      throw new Error('没有可用的刷新令牌');
    }

    const response = await this.post<RefreshTokenResponse>(
      API_ENDPOINTS.auth.refreshToken,
      { refresh_token: this.refreshToken } as RefreshTokenRequest,
      { withAuth: false }
    );

    if (response.data) {
      this.setTokens(response.data.access_token, response.data.refresh_token);
    }
  }

  /**
   * 验证token有效性
   * @returns {Promise<ApiResponse<TokenVerifyResponse>>} token验证响应
   */
  async verifyToken(): Promise<ApiResponse<TokenVerifyResponse>> {
    try {
      console.log('开始验证 token...');
      const token = this.getAccessToken();
      console.log('当前 token:', token ? '已设置' : '未设置');
      
      if (!token) {
        console.warn('Token 未设置，无法验证');
        return {
          code: 401,
          message: 'Token未设置',
          data: { 
            valid: false, 
            user: {
              id: '',
              username: '',
              phone: '',
              role: 'user',
              status: 'active'
            }
          }
        };
      }
      
      const response = await this.get<TokenVerifyResponse>(API_ENDPOINTS.auth.verifyToken);
      console.log('Token 验证响应:', response);
      return response;
    } catch (error) {
      console.error('Token 验证失败:', error);
      return {
        code: 401,
        message: 'Token验证失败',
        data: { 
          valid: false, 
          user: {
            id: '',
            username: '',
            phone: '',
            role: 'user',
            status: 'active'
          }
        }
      };
    }
  }

  /**
   * 获取访问令牌
   * @returns {string | null} 访问令牌或 null
   */
  getAccessToken(): string | null {
    if (typeof window !== "undefined") {
      const cookies = document.cookie.split(';');
      const tokenCookie = cookies.find(cookie => cookie.trim().startsWith('access_token='));
      if (tokenCookie) {
        return tokenCookie.split('=')[1];
      }
    }
    return null;
  }

  /**
   * 获取刷新令牌
   * @returns {string | null} 刷新令牌或 null
   */
  getRefreshToken(): string | null {
    if (typeof window !== "undefined") {
      const cookies = document.cookie.split(';');
      const tokenCookie = cookies.find(cookie => cookie.trim().startsWith('refresh_token='));
      if (tokenCookie) {
        return tokenCookie.split('=')[1];
      }
    }
    return null;
  }

  /**
   * 用户登录
   * @param {LoginRequest} data - 登录请求数据
   * @returns {Promise<ApiResponse<LoginResponse>>} 登录响应，包含用户信息和认证令牌
   */
  async login(data: LoginRequest): Promise<ApiResponse<LoginResponse>> {
    const response = await this.post<LoginResponse>(
      API_ENDPOINTS.auth.login,
      data,
      { withAuth: false }
    );

    if (response.data) {
      this.setTokens(response.data.access_token, response.data.refresh_token);
    }
    return response;
  }

  /**
   * 用户注册
   * @param {RegisterRequest} data - 注册请求数据
   * @returns {Promise<ApiResponse<void>>} 注册响应
   */
  async register(data: RegisterRequest): Promise<ApiResponse<void>> {
    return this.post<void>(API_ENDPOINTS.auth.register, data, {
      withAuth: false,
    });
  }

  /**
   * 发送验证码
   * @param {SendVerificationCodeRequest} data - 发送验证码请求数据
   * @returns {Promise<ApiResponse<void>>} 发送验证码响应
   */
  async sendVerificationCode(
    data: SendVerificationCodeRequest
  ): Promise<ApiResponse<void>> {
    return this.post<void>(API_ENDPOINTS.auth.sendVerificationCode, data, {
      withAuth: false,
    });
  }

  /**
   * 验证验证码
   * @param {VerificationCodeRequest} data - 验证码验证请求数据
   * @returns {Promise<ApiResponse<void>>} 验证码验证响应
   */
  async verifyCode(data: VerificationCodeRequest): Promise<ApiResponse<void>> {
    return this.post<void>(API_ENDPOINTS.auth.verifyCode, data, {
      withAuth: false,
    });
  }

  /**
   * 重置密码
   * @param {ResetPasswordRequest} data - 重置密码请求数据
   * @returns {Promise<ApiResponse<void>>} 重置密码响应
   */
  async resetPassword(data: ResetPasswordRequest): Promise<ApiResponse<void>> {
    return this.post<void>(API_ENDPOINTS.auth.resetPassword, data, {
      withAuth: false,
    });
  }

  /**
   * 用户登出
   * 发送登出请求并清除本地认证信息
   * @returns {Promise<ApiResponse<void>>}
   */
  async logout(): Promise<ApiResponse<void>> {
    try {
      const request: LogoutRequest = {
        access_token: this.accessToken || undefined,
        refresh_token: this.refreshToken || undefined
      };
      const response = await this.post<void>(API_ENDPOINTS.auth.logout, request, { withAuth: true });
      return response;
    } finally {
      this.clearTokens();
    }
  }

  /**
   * 修改密码
   * @param params 密码参数
   */
  async changePassword(params: {
    oldPassword: string;
    newPassword: string;
  }): Promise<ApiResponse<void>> {
    const request: ChangePasswordRequest = {
      old_password: params.oldPassword,
      new_password: params.newPassword
    };
    return this.post<void>(API_ENDPOINTS.auth.changePassword, request, { withAuth: true });
  }

  /**
   * 获取当前用户信息
   * @returns {Promise<ApiResponse<User>>} 用户信息
   */
  async getCurrentUser(): Promise<ApiResponse<User>> {
    const response = await this.get<User>(API_ENDPOINTS.auth.me);
    return response;
  }

  /**
   * 检查用户是否已认证
   * @returns {boolean} 如果用户已认证返回 true，否则返回 false
   */
  isAuthenticated(): boolean {
    return !!this.accessToken && !!this.refreshToken;
  }

  // 添加事件监听方法
  on(event: string, listener: (...args: any[]) => void) {
    this.eventEmitter.on(event, listener);
  }

  // 移除事件监听方法
  off(event: string, listener: (...args: any[]) => void) {
    this.eventEmitter.off(event, listener);
  }

}

/** 导出 AuthService 单例实例 */
export const authService = AuthService.getInstance();
